package com.example.spring_mybatis.mapper;

import org.apache.ibatis.annotations.InsertProvider;
import org.apache.ibatis.binding.MapperMethod;
import org.apache.ibatis.javassist.tools.reflect.Metaobject;
import org.apache.ibatis.javassist.tools.reflect.Reflection;
import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.mapping.ParameterMapping;
import org.apache.ibatis.mapping.SqlSource;
import org.apache.ibatis.reflection.MetaObject;
import org.apache.ibatis.reflection.SystemMetaObject;
import org.apache.ibatis.session.Configuration;
import org.apache.ibatis.type.ObjectTypeHandler;
import org.springframework.util.ReflectionUtils;

import java.lang.reflect.Field;
import java.util.Collections;
import java.util.List;

/**
 * @author onoo
 * @create 2021-08-15
 **/
public interface BaseInsertMapper<T> {

    @InsertProvider(type = InsertSqlProvider.class,method = "dynamicSQL")
    int insert(T o);

    class InsertSqlProvider{

        public void insert(MappedStatement ms){
            InsertProvideSqlSource provideSqlSource = new InsertProvideSqlSource (ms);
            setSqlSource(ms,provideSqlSource);
        }

        private void setSqlSource(MappedStatement ms, SqlSource sqlSource) {
            MetaObject msObject = SystemMetaObject.forObject(ms);
            msObject.setValue("sqlSource", sqlSource);
        }

        public String dynamicSQL(Object recode){
            return "dynamicSQL";

        }

    }

    class InsertProvideSqlSource implements SqlSource {

        private MappedStatement ms;

        public InsertProvideSqlSource(MappedStatement ms) {
            this.ms = ms;
        }

        @Override
        public BoundSql getBoundSql(Object parameterObject) {
            Configuration configuration = ms.getConfiguration ();
            Class<?> tCls = parameterObject.getClass ();
//            List<String> columns =  ;
            String simpleName = tCls.getSimpleName ().toLowerCase ();
            StringBuilder sb = new StringBuilder ();
            sb.append ("insert into ");
            sb.append (simpleName);
            sb.append (" (");
            sb.append ("name");
            sb.append (")  values(?)");
            ParameterMapping parameterMapping = new ParameterMapping.Builder (configuration, "name", String.class)
                    .typeHandler (new ObjectTypeHandler ())
                    .build ();
            MapperMethod.ParamMap paramMap = new MapperMethod.ParamMap ();
            Field field = ReflectionUtils.findField (tCls, "name");
            field.setAccessible (true);
            paramMap.put ("name", ReflectionUtils.getField (field,parameterObject));
            BoundSql boundSql = new BoundSql (configuration,sb.toString (), Collections.singletonList (parameterMapping),paramMap);
            return boundSql;
        }
    }



}
